// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package types2

import "cmd/compile/internal/syntax"

// ---------------------------------------------------------------
// API 

// 签名表示（非内置）函数或方法类型。
// 在比较签名的身份时，接收器被忽略。
type Signature struct {
	// 我们需要将作用域保留在签名中（而不是将其传递给
	// 并将其存储在Func对象中），因为当类型检查函数
	// literal时，我们调用返回一般类型的通用类型检查程序。
	// 然后我们解压*签名，并使用文本体的作用域。
	rparams  *TypeParamList // 接收器类型参数从左到右，或nil 
	tparams  *TypeParamList // 类型参数从左到右，或nil 
	scope    *Scope         // 用于包本地和非实例化签名的函数范围；nil否则
	recv     *Var           // nil如果不是方法
	params   *Tuple         // （传入）参数从左到右；或从左至右无
	results  *Tuple         // （传出）结果；或者nil 
	variadic bool           // 如果最后一个参数的类型为。。。T（或字符串，仅用于append内置）
}

// NewSignatureType为给定的接收器创建新的函数类型，
// receiver type parameters、type parameters、parameters和results。如果设置了
// 变量，则参数必须至少包含一个参数，最后一个
// 参数必须是未命名的切片类型。如果recv为非nil，则typeParams必须
// 为空。如果recvTypeParams为非空，则recv必须为非nil。
func NewSignatureType(recv *Var, recvTypeParams, typeParams []*TypeParam, params, results *Tuple, variadic bool) *Signature {
	if variadic {
		n := params.Len()
		if n == 0 {
			panic("variadic function must have at least one parameter")
		}
		if _, ok := params.At(n - 1).typ.(*Slice); !ok {
			panic("variadic parameter must be of unnamed slice type")
		}
	}
	sig := &Signature{recv: recv, params: params, results: results, variadic: variadic}
	if len(recvTypeParams) != 0 {
		if recv == nil {
			panic("function with receiver type parameters must have a receiver")
		}
		sig.rparams = bindTParams(recvTypeParams)
	}
	if len(typeParams) != 0 {
		if recv != nil {
			panic("function with type parameters cannot have a receiver")
		}
		sig.tparams = bindTParams(typeParams)
	}
	return sig
}

// Recv返回签名s的接收者（如果是方法），或者如果是
// 函数，则返回nil。在比较签名以确定身份时，会忽略此选项。
// 
// 对于抽象方法，Recv以*命名或*接口的形式返回封闭接口
// 。由于嵌入，一个接口可能包含接收器类型不同的方法。
func (s *Signature) Recv() *Var { return s.recv }

// TypeParams返回签名s的类型参数，或nil。
func (s *Signature) TypeParams() *TypeParamList { return s.tparams }

// SetTypeParams设置签名s的类型参数。
func (s *Signature) SetTypeParams(tparams []*TypeParam) { s.tparams = bindTParams(tparams) }

// RecvTypeParams返回签名s的接收方类型参数，或为零。
func (s *Signature) RecvTypeParams() *TypeParamList { return s.rparams }

// Params返回签名s的参数，或nil。
func (s *Signature) Params() *Tuple { return s.params }

// Results返回签名s或nil的结果。
func (s *Signature) Results() *Tuple { return s.results }

// 可变报告签名s是否可变。
func (s *Signature) Variadic() bool { return s.variadic }

func (s *Signature) Underlying() Type { return s }
func (s *Signature) String() string   { return TypeString(s, nil) }

// ----------------------------------------------------------------------------------------
// 实现

// funcType检查函数或方法类型。
func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []*syntax.Field, ftyp *syntax.FuncType) {
	check.openScope(ftyp, "function")
	check.scope.isFunc = true
	check.recordScope(ftyp, check.scope)
	sig.scope = check.scope
	defer check.closeScope()

	if recvPar != nil {
		// collect generic receiver type parameters，如果任何
		// -一个receiver type parameters与任何其他类型参数类似，只是它是隐式声明的
		// -receiver specification充当其类型参数的本地声明，可能是空的
		_, rname, rparams := check.unpackRecv(recvPar.Type, true)
		if len(rparams) > 0 {
			tparams := make([]*TypeParam, len(rparams))
			for i, rparam := range rparams {
				tparams[i] = check.declareTypeParam(rparam)
			}
			sig.rparams = bindTParams(tparams)
			// /空标识符不被声明，因此，在Checker中，对
			// 接收方类型表达式的简单类型检查将失败。下面的collectParams，
			// 当检查时。ident无法将u解析为类型。
			// 
			// 。recvTParamMap将这些空白标识符映射到它们的类型参数
			// 类型，以便在Checker中解析它们。当它们在作用域中查找失败时识别
			// 。
			for i, p := range rparams {
				if p.Value == "_" {
					if check.recvTParamMap == nil {
						check.recvTParamMap = make(map[*syntax.Name]*TypeParam)
					}
					check.recvTParamMap[p] = tparams[i]
				}
			}
			// 确定接收器类型以获取其类型参数
			// 和相应的类型参数边界
			var recvTParams []*TypeParam
			if rname != nil {
				// recv应该是命名类型（否则其他地方会报告错误）
				// 另外：不要通过genericType报告错误，因为在我们键入检查签名时会再次报告
				// 错误。
				// TODO（gri）也许应该将接收器标记为无效？
				if recv, _ := check.genericType(rname, false).(*Named); recv != nil {
					recvTParams = recv.TypeParams().list()
				}
			}
			// 提供类型参数边界
			if len(tparams) == len(recvTParams) {
				smap := makeRenameMap(recvTParams, tparams)
				for i, tpar := range tparams {
					recvTPar := recvTParams[i]
					check.mono.recordCanon(tpar, recvTPar)
					// recvTPar。bound（可能）在
					// 接收器类型声明的上下文中参数化。替换当前
					// 上下文的参数。
					tpar.bound = check.subst(tpar.obj.pos, recvTPar.bound, smap, nil)
				}
			} else if len(tparams) < len(recvTParams) {
				// 在这里报告错误是一种权宜之计，可以在以后无法推断类型参数/参数时避免
				// 编译器崩溃。它可能导致后续错误（参见问题#51339，#51343）。
				// TODO（gri）找到更好的解决方案
				got := measure(len(tparams), "type parameter")
				check.errorf(recvPar, "got %s, but receiver base type declares %d", got, len(recvTParams))
			}
		}
	}

	if tparams != nil {
		// 解析器会抱怨方法的类型参数无效。
		check.collectTypeParams(&sig.tparams, tparams)
	}

	// 值（非类型）参数的作用域从函数体开始。为他们的
	// 声明，然后将该范围压缩到父范围中（并在
	// 报告当时的任何重新声明）。
	scope := NewScope(check.scope, nopos, nopos, "function body (temp. scope)")
	var recvList []*Var // TODO（gri）不需要在此处列出
	if recvPar != nil {
		recvList, _ = check.collectParams(scope, []*syntax.Field{recvPar}, false) // 使用重写的接收器类型，如果存在任何
	}
	params, variadic := check.collectParams(scope, ftyp.ParamList, true)
	results, _ := check.collectParams(scope, ftyp.ResultList, false)
	scope.Squash(func(obj, alt Object) {
		var err error_
		err.errorf(obj, "%s redeclared in this block", obj.Name())
		err.recordAltDecl(alt)
		check.report(&err)
	})

	if recvPar != nil {
		// recv参数列表（可能为空）
		// spec：“通过
		// method name前面的额外参数部分指定接收方。该参数部分必须声明一个参数，即接收方。”
		var recv *Var
		switch len(recvList) {
		case 0:
			// 解析程序报告的错误
			recv = NewParam(nopos, nil, "", Typ[Invalid]) // 忽略下面的recv 
		default:
			// 多个接收器
			check.error(recvList[len(recvList)-1].Pos(), "method must have exactly one receiver")
			fallthrough // 继续使用第一个接收器
		case 1:
			recv = recvList[0]
		}
		sig.recv = recv

		// 延迟接收器类型的验证，因为它可能会导致接收器类型所依赖的类型过早扩展
		// 请参阅问题#51232，#51233。
		check.later(func() {
			rtyp, _ := deref(recv.typ)

			// spec:“接收器类型必须采用T或*T格式，其中T是类型名称。”
			// （忽略无效类型-之前报告了错误）
			if rtyp != Typ[Invalid] {
				var err string
				switch T := rtyp.(type) {
				case *Named:
					T.resolve(check.bestContext(nil))
					// 接收器类型可能是通过别名引用到
					// 的实例化类型（目前无法具有接收器参数）。
					if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
						check.errorf(recv.pos, "cannot define methods on instantiated type %s", recv.typ)
						break
					}
					// spec:“用T表示的类型称为接收器基类型；它不能是指针或接口类型，必须在与方法相同的包
					// 中声明。”
					if T.obj.pkg != check.pkg {
						err = "type not defined in this package"
						if check.conf.CompilerErrorMessages {
							check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
							err = ""
						}
					} else {
						// 接收方基类型的基础类型可以是类型参数；
						// 例如，对于带有类型为T[P any]P的泛型接收器T[P]的方法。
						// TODO（gri）目前不允许此类声明。
						// 重新审视underIs的需求。
						underIs(T, func(u Type) bool {
							switch u := u.(type) {
							case *Basic:
								// 不安全。指针被视为常规指针
								if u.kind == UnsafePointer {
									err = "unsafe.Pointer"
									return false
								}
							case *Pointer, *Interface:
								err = "pointer or interface type"
								return false
							}
							return true
						})
					}
				case *Basic:
					err = "basic or unnamed type"
					if check.conf.CompilerErrorMessages {
						check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
						err = ""
					}
				default:
					check.errorf(recv.pos, "invalid receiver type %s", recv.typ)
				}
				if err != "" {
					check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err)
				}
			}
		}).describef(recv, "validate receiver %s", recv)
	}

	sig.params = NewTuple(params...)
	sig.results = NewTuple(results...)
	sig.variadic = variadic
}

// collectParams在作用域中声明list的参数，并返回相应的
// variable list。
func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, variadicOk bool) (params []*Var, variadic bool) {
	if list == nil {
		return
	}

	var named, anonymous bool

	var typ Type
	var prev syntax.Expr
	for i, field := range list {
		ftype := field.Type
		// 类型检查分组字段的类型只检查一次
		if ftype != prev {
			prev = ftype
			if t, _ := ftype.(*syntax.DotsType); t != nil {
				ftype = t.Elem
				if variadicOk && i == len(list)-1 {
					variadic = true
				} else {
					check.softErrorf(t, "can only use ... with final parameter in list")
					// 忽略。。。继续
				}
			}
			typ = check.varType(ftype)
		}
		// 解析器确保f.Tag为nil，我们不关心构造的AST是否包含非nil标记。
		if field.Name != nil {
			// 命名参数
			name := field.Name.Value
			if name == "" {
				check.error(field.Name, invalidAST+"anonymous parameter")
				// 确定继续
			}
			par := NewParam(field.Name.Pos(), check.pkg, name, typ)
			check.declare(scope, field.Name, par, scope.pos)
			params = append(params, par)
			named = true
		} else {
			// 匿名参数
			par := NewParam(field.Pos(), check.pkg, "", typ)
			check.recordImplicit(field, par)
			params = append(params, par)
			anonymous = true
		}
	}

	if named && anonymous {
		check.error(list[0], invalidAST+"list contains both named and anonymous parameters")
		// 确定继续
	}

	// 对于变量函数，将最后一个参数的类型从T更改为[]T。
	// 因为我们选择了T而不是。。。T、 我们还需要追溯
	// 记录。。。T.
	if variadic {
		last := params[len(params)-1]
		last.typ = &Slice{elem: last.typ}
		check.recordTypeAndValue(list[len(list)-1].Type, typexpr, last.typ, nil)
	}

	return
}
